package com.ww.reactor.threads;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

public class Handler implements Runnable {

    static ThreadPoolExecutor poolExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() + 1);

    static final int PROCESSING = 3;

    final SocketChannel socketChannel;

    final SelectionKey selectionKey;

    ByteBuffer input = ByteBuffer.allocate(1024);

    ByteBuffer output = ByteBuffer.allocate(1024);

    static final int READING = 0, SENDING = 1;

    int state = READING;

    public Handler(SocketChannel sc, Selector s) throws IOException {
        socketChannel = sc;
        socketChannel.configureBlocking(false);
        selectionKey = socketChannel.register(s, 0);
        selectionKey.attach(this);
        selectionKey.interestOps(SelectionKey.OP_READ);
        s.wakeup();
    }

    @Override
    public void run() {
        try {
            if (state == READING) {
                read();
            } else if (state == SENDING) {
                send();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    void read() throws Exception {
        socketChannel.read(input);
        if (inputIsComplete()) {
            state = PROCESSING;
            poolExecutor.execute(new Processor());
        }
    }

    void send() throws Exception {
        socketChannel.write(output);
        if (outputIsComplete()) {
            selectionKey.cancel();
        }
    }

    boolean inputIsComplete() {
        return true;
    }

    boolean outputIsComplete() {
        return true;
    }

    void process() {}

    static class Processor implements Runnable {

        @Override
        public void run() {

        }
    }
}
